/**
 * @file       main.c
 * @author     mz8023yt
 * @email      mz8023yt@163.com
 * @version    V1.0
 * @date       2022-03-13
 * @brief      st7735 lcd test
 */

#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "st7735.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "colorbar.h"

#define ST7735_CLK_PIN 2
#define ST7735_MOSI_PIN 3
#define ST7735_RST_PIN 10
#define ST7735_DC_PIN 6
#define ST7735_CS_PIN 7
#define ST7735_BL_PIN 11

static spi_device_handle_t spi;

void esp32c3_spi_write(uint8_t *bytes, uint32_t len)
{
	uint32_t section = 4096;
	spi_transaction_t t;

	if (!len) {
		return;
	}

	while (len > section)
	{
		memset(&t, 0, sizeof(t));			  // Zero out the transaction
		t.length = 8 * section;				  // Command is 8 bits
		t.tx_buffer = bytes;				  // The data is the cmd itself
		spi_device_polling_transmit(spi, &t); // Transmit!
		bytes += section;
		len -= section;
	}

	memset(&t, 0, sizeof(t));			  // Zero out the transaction
	t.length = 8 * len;					  // Command is 8 bits
	t.tx_buffer = bytes;				  // The data is the cmd itself
	spi_device_polling_transmit(spi, &t); // Transmit!
}

void esp32c3_rst_pin(int val)
{
	gpio_set_level(ST7735_RST_PIN, val);
}

void esp32c3_dc_pin(int val)
{
	gpio_set_level(ST7735_DC_PIN, val);
}

void esp32c3_bl_pin(int val)
{
	gpio_set_level(ST7735_BL_PIN, val);
}

void esp32c3_msleep(int ms)
{
	usleep(1000 * ms);
}

void board_init()
{
	/* gpio */
	gpio_reset_pin(ST7735_RST_PIN);
	gpio_set_direction(ST7735_RST_PIN, GPIO_MODE_OUTPUT);

	gpio_reset_pin(ST7735_DC_PIN);
	gpio_set_direction(ST7735_DC_PIN, GPIO_MODE_OUTPUT);

	gpio_reset_pin(ST7735_BL_PIN);
	gpio_set_direction(ST7735_BL_PIN, GPIO_MODE_OUTPUT);

	spi_bus_config_t buscfg = {
		.miso_io_num = -1,
		.mosi_io_num = ST7735_MOSI_PIN,
		.sclk_io_num = ST7735_CLK_PIN,
		.quadwp_io_num = -1,
		.quadhd_io_num = -1,
		.max_transfer_sz = 4096,
	};

	spi_device_interface_config_t devcfg = {
		.clock_speed_hz = 60000000,	   // SPI Clock
		.mode = 0,					   // SPI mode
		.spics_io_num = ST7735_CS_PIN, // CS pin
		.queue_size = 7,			   // We want to be able to queue 7 transactions at a time
	};

	spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
	spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
}

void app_main(void)
{
	struct st7735 lcd;
	uint8_t *buf_h = NULL;
	uint8_t *buf_v = NULL;

	board_init();

	/* set lcd param */
	/**
	 * ST7735 总分辨率大小为 162x132
	 *
	 * (132 - 80) / 2 = 26
	 * (162 - 160) / 2 = 1
	 */
	lcd.cfg.fix.width = 80;
	lcd.cfg.fix.height = 160;
	lcd.cfg.fix.xshift = 26;
	lcd.cfg.fix.yshift = 1;
	lcd.cfg.var.orien = 0;

	/* register the operation */
	lcd.ops.pin.rst = esp32c3_rst_pin;
	lcd.ops.pin.dc = esp32c3_dc_pin;
	lcd.ops.pin.bl = esp32c3_bl_pin;
	lcd.ops.time.msleep = esp32c3_msleep;
	lcd.ops.spi.write = esp32c3_spi_write;
	st7735_init(&lcd);

	/* display colorbar */
	buf_h = malloc(lcd.cfg.fix.width * lcd.cfg.fix.height * 2);
	colorbar_generate(buf_h, lcd.cfg.fix.height, lcd.cfg.fix.width);

	buf_v = malloc(lcd.cfg.fix.width * lcd.cfg.fix.height * 2);
	colorbar_generate(buf_v, lcd.cfg.fix.width, lcd.cfg.fix.height);

	while (1)
	{
		st7735_rotate_set(&lcd, ROTATE_0);
		st7735_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, (uint16_t*)buf_v);
		vTaskDelay(1000 / portTICK_PERIOD_MS);

		st7735_rotate_set(&lcd, ROTATE_90);
		st7735_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, (uint16_t*)buf_h);
		vTaskDelay(1000 / portTICK_PERIOD_MS);

		st7735_rotate_set(&lcd, ROTATE_180);
		st7735_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, (uint16_t*)buf_v);
		vTaskDelay(1000 / portTICK_PERIOD_MS);

		st7735_rotate_set(&lcd, ROTATE_270);
		st7735_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, (uint16_t*)buf_h);
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	}
}
